package spring.cloud.tasks.tasks_manager.schedule;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import spring.cloud.tasks.common.DateUtils;
import spring.cloud.tasks.common.TaskStageInfo;
import spring.cloud.tasks.common.status.TaskInstanceInfoStatus;
import spring.cloud.tasks.common.task_item_allot.TaskItem;
import spring.cloud.tasks.tasks_manager.waitingPreAssignTasks.SlidingTimeTaskBucket;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * 实例结构
 * 批次任务id+实例id
 * 批次任务id+实例id+stage
 * 批次任务id+实例id+stage+type+taskItemIndex 状态跟踪信息
 */

/**
 * 单个任务执行成功或者失败或者超时 那么新的实例就可以进行替代。
 */
@Slf4j
@Setter
@Getter
public class TaskInstanceInfo {
    public Lock lock = new ReentrantLock();
    public static final String RUN_TYPE_TIME_SCHEDULE = "time_schedule";
    public static final String RUN_TYPE_RIGHT_NOW_RUN = "right_now_run";
    private String taskType;
    private String stateFullTask = "N";//默认都是无状态的任务(简单分片任务)
    private String taskId;
    private String taskLevel;
    //
    private String taskProperties;
    private String taskDataRangeRule;
    private String taskItemInfo;
    //
    //
    private int timeoutMinutes;//超时时间
    private int lockMinutes;//lock时间,相对超时时间的增量
    private int clearMinutes;//相对lock时间的增量
    //
    private long version;
    private Date nextPreAssignDate;
    private long preAssignTimeStamp;
    private Date nextFireDate;//首次执行的时间
    private Date timeoutDateTime;//超时时间
    private Date lockDateTime;//lock时间
    private Date clearDateTime;


    public boolean isTimeout() {
        return System.currentTimeMillis() - (this.nextFireDate.getTime() + DateUtils.MINUTE * this.timeoutMinutes) >= 0;
    }

    public boolean isReachLockLoseEfficacyTime() {
        /**
         * 实例信息需要进行清理，避免内存溢出，如果执行器一致没有和ZK反馈数据,那么调度器自动计算是否超时。
         */
        return System.currentTimeMillis() - (
                this.nextFireDate.getTime() + //
                        DateUtils.MINUTE * this.timeoutMinutes + //
                        DateUtils.MINUTE * this.lockMinutes
        ) > 0;
    }

    public boolean isReachClearTime() {
        /**
         * 实例信息需要进行清理，避免内存溢出，如果执行器一致没有和ZK反馈数据,那么调度器自动计算是否超时。
         */
        return System.currentTimeMillis() - (
                this.nextFireDate.getTime() + //
                        DateUtils.MINUTE * this.timeoutMinutes + //
                        DateUtils.MINUTE * this.lockMinutes + //
                        DateUtils.MINUTE * clearMinutes//
        ) > 0;
    }

    /**
     * 当状态为终态的时候需要进行清理。1内存清理，2DB更新任务实例为终态清理（进行ZK和内存和数据库状态一致对比）
     *
     * @return
     */
    public volatile boolean cleared = false;
    //
    private String runType = RUN_TYPE_TIME_SCHEDULE;
    private String taskInstanceId;
    private String oldTaskInstanceId;//重跑这个值不为空
    /**
     * 注册实例阶段分片信息后,更新该值为true,如果调度器挂了。则需要根据当前实例状态更新是否已经注册了。
     */
    private boolean registered = false;
    //待生成实例信息 待预调度  预调度中 禁用取消 完成任务
    private String registerErrorInfo = "";
    private int tryCreateInstanceInfoTime = 0;
    public boolean schedule = false;    //
    public volatile SlidingTimeTaskBucket slidingTimeTaskBucket;

    public boolean removeFromSlidingTimeTaskBucket() {
        if (slidingTimeTaskBucket != null) {
            try {
                this.slidingTimeTaskBucket.getTaskInfoList().remove(this);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                slidingTimeTaskBucket = null;//对象引用=null
            }
        }
        return false;
    }

    private volatile String status = TaskInstanceInfoStatus.$register_task_instance_info_success$;
    //
    private String currentStage;
    private TaskStageInfo currentTaskStageInfo;
    private String currentStageStatus;
    /**
     * 正常批次任务进行状态改变的时候标记 null什么也不做/true需要更新执行计划/false代表结束了
     */
    private Boolean rebuildAssignTaskItemPlanCreate = null;//
    private List<TaskItem> taskItemList = new ArrayList<>();


    /**
     * 先标记取消。真正的状态维护线程会根据取消方式和当前任务的状态，进行是否真正进行取消。
     * mark模式，需要保证系统总会有个线程看到该标记被打上了，然后进行处理。
     */
    public volatile boolean tryCancel = false;
    public volatile Date tryCancelDate = null;
    public volatile boolean needCancel = false;//打上了tryCancel需要根据真实的情况进行判断是否需要取消needCancel。
    //取消的原因。可能多种原因进行取消。
    public volatile Map<String, Object> tryCancelMap = new ConcurrentHashMap<>();
    public volatile boolean cancelled = false;
    public volatile Date cancelDate = null;
    public volatile boolean cancelledAndSynchronizedZk = false;//同步到ZK了

}
